// Copyright  2004-2008 Backplane Ltd.
//
// This file is part of Ubiquity formsPlayer
//
// Ubiquity formsPlayer is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at your
// option) any later version.
//
// Ubiquity formsPlayer is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License
// along with Ubiquity formsPlayer If not, see <http://www.gnu.org/licenses/>.
//	
//
//   Purpose: implementation of CXFormsElementModel.
//   $Id$


#include "stdafx.h"
#include "XFormsApp.h"
#include "ModelUI.h"
#include "FP_ReturnCodes.h"
#include "FP_Definitions.h"
#include <new>
#include "eventmsg.h"
#include "ImplInstance.h"
#include "InstanceCollection.h"
#include "entrypoint.h"

//All entry/exit points in formsPlayer are surrounded by try/catch blocks 
//	to prevent exposure of exceptions to the calling application.
//

//#defining EXPOSE_ALL_MODEL_ENTRY_EXIT_EXCEPTIONS removes the try/catch from 
//	all CXFormsElementModel entrypoints to help an investigator find the original
//	exception.

#define EXPOSE_ALL_MODEL_ENTRY_EXIT_EXCEPTIONS
#undef EXPOSE_ALL_MODEL_ENTRY_EXIT_EXCEPTIONS

#ifdef EXPOSE_ALL_MODEL_ENTRY_EXIT_EXCEPTIONS
	#define FORMSPLAYER_ENTRY_POINT_MODEL
	#define FORMSPLAYER_EXIT_POINT_MODEL
#else
	#define FORMSPLAYER_ENTRY_POINT_MODEL FORMSPLAYER_ENTRY_POINT
	#define FORMSPLAYER_EXIT_POINT_MODEL FORMSPLAYER_EXIT_POINT
#endif

//Each of the entry points in CXFormsElement Model can be indipendently be switched
//	on or off, by removing _MODEL from the definitions.

#define FORMSPLAYER_ENTRY_POINT_REBUILD FORMSPLAYER_ENTRY_POINT_MODEL
#define FORMSPLAYER_EXIT_POINT_REBUILD FORMSPLAYER_EXIT_POINT_MODEL

#define FORMSPLAYER_ENTRY_POINT_RECALCULATE FORMSPLAYER_ENTRY_POINT_MODEL
#define FORMSPLAYER_EXIT_POINT_RECALCULATE FORMSPLAYER_EXIT_POINT_MODEL

#define FORMSPLAYER_ENTRY_POINT_REVALIDATE FORMSPLAYER_ENTRY_POINT_MODEL
#define FORMSPLAYER_EXIT_POINT_REVALIDATE FORMSPLAYER_EXIT_POINT_MODEL

#define FORMSPLAYER_ENTRY_POINT_REFRESH FORMSPLAYER_ENTRY_POINT_MODEL
#define FORMSPLAYER_EXIT_POINT_REFRESH FORMSPLAYER_EXIT_POINT_MODEL

#define FORMSPLAYER_ENTRY_POINT_GETINSTANCEDOCUMENT FORMSPLAYER_ENTRY_POINT_MODEL
#define FORMSPLAYER_EXIT_POINT_GETINSTANCEDOCUMENT FORMSPLAYER_EXIT_POINT_MODEL

#define FORMSPLAYER_ENTRY_POINT_PUTINSTANCEDOCUMENT FORMSPLAYER_ENTRY_POINT_MODEL
#define FORMSPLAYER_EXIT_POINT_PUTINSTANCEDOCUMENT FORMSPLAYER_EXIT_POINT_MODEL

extern CXFormsApp theApp;


CXFormsElementModel::CXFormsElementModel()
:m_bSoftbarInvoked(false)
,m_bParseDone(false)
{
}

CXFormsElementModel::~CXFormsElementModel()
{
}

STDMETHODIMP CXFormsElementModel::getInstanceDocument(VARIANT vInstanceId, IXMLDOMDocument** ppDoc)
{
	switch(vInstanceId.vt)
	{
		case VT_BSTR:
			return getInstanceDocument(vInstanceId.bstrVal,ppDoc);
		case VT_EMPTY:
		case VT_ERROR:
		case VT_NULL:
			return getInstanceDocument(0, ppDoc);
		default:
			return E_FAIL;
	}
	
}

STDMETHODIMP CXFormsElementModel::getInstanceDocument(BSTR sInstanceId, IXMLDOMDocument** ppDoc)
{
	HRESULT hr = S_OK;
	FORMSPLAYER_ENTRY_POINT_GETINSTANCEDOCUMENT

	if(!m_pXForms || !m_pXForms->canContinue())
		hr = E_FAIL;
	else 
	{
		*ppDoc = NULL;
		if(m_pImpl) {
			CImplInstance * pInst = static_cast<CImplModel*>(m_pImpl)->getInstance(sInstanceId);
			if(pInst) 
			{
				CDOM3Document * pDomLive = pInst->GetLiveDOM();
				if(pDomLive)
				{
					hr = pDomLive->m_pXMLParser.CopyTo(ppDoc);
				}
			}
		}
	}

	FORMSPLAYER_EXIT_POINT_GETINSTANCEDOCUMENT
	return hr;
}


STDMETHODIMP CXFormsElementModel::rebuild(void)
{
	HRESULT hr = E_FAIL;
	FORMSPLAYER_ENTRY_POINT_REBUILD
	if(m_pImpl)
	{
		hr = reinterpret_cast<CImplModel*>(m_pImpl)->rebuild(false);
		m_pXForms->RunDeferredUpdate(); 
	}
	FORMSPLAYER_EXIT_POINT_REBUILD
	return hr;
}
STDMETHODIMP CXFormsElementModel::recalculate(void)
{
	HRESULT hr = E_FAIL;
	FORMSPLAYER_ENTRY_POINT_RECALCULATE
	if(m_pImpl)
	{
		hr = reinterpret_cast<CImplModel*>(m_pImpl)->recalculate(false);
		m_pXForms->RunDeferredUpdate();
	}
	FORMSPLAYER_EXIT_POINT_RECALCULATE
	return hr;
}

STDMETHODIMP CXFormsElementModel::revalidate(void)
{
	HRESULT hr = E_FAIL;	
	FORMSPLAYER_ENTRY_POINT_REVALIDATE
	if(m_pImpl)
	{
		hr = reinterpret_cast<CImplModel*>(m_pImpl)->revalidate(false);
		m_pXForms->RunDeferredUpdate();
	}
	FORMSPLAYER_EXIT_POINT_REVALIDATE
	return hr;
}

STDMETHODIMP CXFormsElementModel::refresh(void)
{
	HRESULT hr = E_FAIL;
	FORMSPLAYER_ENTRY_POINT_REFRESH

	if(m_pImpl)
	{
		hr = reinterpret_cast<CImplModel*>(m_pImpl)->refresh(false);
		m_pXForms->RunDeferredUpdate();
	}
	FORMSPLAYER_EXIT_POINT_REFRESH

	return hr;
}

STDMETHODIMP CXFormsElementModel::putInstanceDocument(BSTR instanceId, IXMLDOMDocument *pDocument)
{
	HRESULT hr = S_OK;
	FORMSPLAYER_ENTRY_POINT_PUTINSTANCEDOCUMENT
	if(instanceId && pDocument) {
		if(wcscmp(instanceId, g_lpwszAnonymous)) {
			CImplInstance *pInst;
			CImplModel * pImplModel = dynamic_cast<CImplModel *>(m_pImpl);
			if(pImplModel && (pInst = pImplModel->getInstance(instanceId)))
				hr = pInst->putInstanceDocument(pDocument);
			else {
				hr = FP_E_NOINST;
				SetupErrorInfo(hr, instanceId);
			}
		} else {
			hr = FP_E_ANONINST;
			SetupErrorInfo(hr);
		}
	} else {
		hr = FP_E_BADARG;
		SetupErrorInfo(hr, L"CXFormsElementModel::putInstanceDocument");
	}
	FORMSPLAYER_EXIT_POINT_PUTINSTANCEDOCUMENT
	return hr;
}

STDMETHODIMP CXFormsElementModel::get_instances(IXFormsInstanceCollection **ppInstances)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	HRESULT hr = S_OK;

	if(m_pImpl) {
		if(ppInstances) {
			CComObject<CXFormsInstanceCollection> *pInstancesCOM;
			hr = CComObject<CXFormsInstanceCollection>::CreateInstance(&pInstancesCOM);
			if(SUCCEEDED(hr)) {
				pInstancesCOM->AddRef();

				CMapBSTRToInstancePtr *pInstancesNative = ((CImplModel*)m_pImpl)->getInstanceList();
				if(pInstancesNative) {
					for(CMapBSTRToInstancePtr::iterator i = pInstancesNative->begin(); i != pInstancesNative->end(); ++i) {
						if(i->second) {
							CDOM3Document *pLiveDOM = i->second->GetLiveDOM();
							if(pLiveDOM)
								pInstancesCOM->AddInstance(i->second->m_sId, pLiveDOM->m_pXMLParser);
						}
					}

					pInstancesCOM->QueryInterface(IID_IXFormsInstanceCollection, reinterpret_cast<void **>(ppInstances));
				} else
					hr = E_FAIL;

				pInstancesCOM->Release();
			}
		} else
			hr = E_POINTER;
	} else
		hr = E_POINTER;

	return hr;
}

STDMETHODIMP CXFormsElementModel::getXmlState(IXmlState **ppXmlState)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	HRESULT hr = S_OK;

	if(ppXmlState) {
		CComPtr<IXmlState> pXMLState;
		hr = pXMLState.CoCreateInstance(CLSID_XmlState);
		if(SUCCEEDED(hr))
			*ppXmlState = pXMLState.Detach();
	} else
		hr = E_POINTER;

	return hr;
}

HRESULT CXFormsElementModel::InitBehaviour()
{
	RegisterName(g_bsAttrXFormsElementController);
	if(m_lFormKey)
		theApp.FormsManager().GetForm(m_lFormKey,&m_pXForms);
	if(m_pXForms)
		m_pXForms->AddDeletionListener(this);


	m_pImpl = CreateImpl();
	m_pFormControl = dynamic_cast<CFormControl *> (m_pImpl);
	return RegisterCustomEvents(sm_asEventNames,CXFORMSELEMENTMODEL_EVENTS_LENGTH,m_alEventCookies);
}

HRESULT CXFormsElementModel::ElementReady(void)
{
	HRESULT hr = __super::ElementReady();
	m_bParseDone = true;
	if(m_pXForms && !m_pXForms->Configured()) {
		m_pXForms->Configured(true);
		// Bug 267: Get configuration information before continuing processing.
		CImplModel *pImplMdl = dynamic_cast<CImplModel*>(m_pImpl);
		if(pImplMdl)
			// The CImpl should be responsible for this processing
			hr = pImplMdl->ConfigureForm();

#ifndef FP_LEAN_AND_MEAN_SHOWSPLASH
		if(FAILED(hr))
		{
			m_pXForms->reportException(hr);
		}
#else
		if(SUCCEEDED(hr))
			// All is well so we can display the splash page and carry on processing.
			m_pXForms->showSplash();
		else
			// If an error has occurred we should stop processing since the configuration
			// file [either the default or a custom one] may have been tampered with.
			m_pXForms->reportException(hr);
#endif
	}
	return hr;
}

HRESULT CXFormsElementModel::DocumentReady(void)
{
	HRESULT hr = __super::DocumentReady();

	if(m_pXForms)
	{
		// Bug 901: Now that the hideous purple ball has been reinstated, we must check before adding the graceful new branding.
		if(m_pXForms->m_XFConfig.FormBranding())
			m_pXForms->NeoBrandForm();
		else
			m_pXForms->NeoDeBrandForm();
/*
		// Bug 828: Invoke a softbar if we are configured to do so.
		if(m_pXForms->m_XFConfig.Softbar() && !m_bSoftbarInvoked) {
			CComBSTR sSoftbar;
			sSoftbar.Attach(m_pXForms->m_XFConfig.SoftbarName());
			hr = theApp.FormsManager().InvokeSoftbar(m_pXForms, sSoftbar);
			if(SUCCEEDED(hr))
				m_bSoftbarInvoked = true;
		}
*/	}
	return hr;
}


void CXFormsElementModel::RegisterFindBehaviourRefusal()
{
	//do nothing
#ifdef _DEBUG
	long l = 0;
#endif
}
void CXFormsElementModel::RegisterFindBehaviourAcceptance()
{
	//do nothing
#ifdef _DEBUG
	long l = 0;
#endif
}

